package com.wusuowei.shiro_jwt.controller;


import com.alibaba.fastjson.JSONObject;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wusuowei.shiro_jwt.annotation.CrudLog;
import com.wusuowei.shiro_jwt.common.enums.BusinessType;
import com.wusuowei.shiro_jwt.config.WxConfig;
import com.wusuowei.shiro_jwt.model.po.CodeLoginKey;
import com.wusuowei.shiro_jwt.model.po.Menu;
import com.wusuowei.shiro_jwt.model.po.User;
import com.wusuowei.shiro_jwt.model.po.UserRole;
import com.wusuowei.shiro_jwt.service.MenuService;
import com.wusuowei.shiro_jwt.service.UserRoleService;
import com.wusuowei.shiro_jwt.service.UserService;
import com.wusuowei.shiro_jwt.shiro.JWTToken;
import com.wusuowei.shiro_jwt.utils.*;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @ClassName QrCodeLoginFirstController
 * @Description 微信扫码登录
 * @Author lxt
 * @Date 2021/7/1 23:26
 */
@Slf4j
@RestController
@RequestMapping("qrCodeFirstLogin")
public class QrCodeLoginFirstController {
//    @Autowired
//    private WxConfig wxConfig;
private final WxConfig wxConfig;

    @Autowired
    public QrCodeLoginFirstController(WxConfig wxConfig) {
        this.wxConfig = wxConfig;
        log.info("QrCodeLoginFirstController initialized with WxConfig: {}", wxConfig);
    }
    @Autowired
    private MenuService menuService;
    @Autowired
    private UserService userService;

    @Autowired
    private UserRoleService userRoleService;

    // 模拟数据库存储或者缓存存储
    Map<String, CodeLoginKey> loginMap = new ConcurrentHashMap<>(64);

    /**
     *  获取登录二维码
     * @return
     */
    @GetMapping("/getQrCode")
    public ResultJson getQrCode(){
        try {
            // 获取token开发者
            String accessToken =getAccessToken();
            log.info("Access Token: " + accessToken);
            // 调试信息
            //从方法中获取试试
            WxConfig wxConfig1=getWxConfig();
            // 确认 wxConfig 是否为空
            if (wxConfig1 == null) {
                log.error("wxConfig1 is null!");
                return ResultJson.error("wxConfig1 is not initialized");
            }

            log.info("WxConfig1: " + wxConfig1.toString());
            log.info("QR Code URL from config1: " + wxConfig1.getQrCodeUrl());
            String getQrCodeUrl = wxConfig1.getQrCodeUrl().replace("TOKEN", accessToken);
            // 调试信息
            log.info("QR Code URL: " + getQrCodeUrl);
            // 这里生成一个带参数的二维码，参数是scene_str
            String sceneStr = CodeLoginUtil.getRandomString(8);
            String json="{\"expire_seconds\": 604800, \"action_name\": \"QR_STR_SCENE\"" +", \"action_info\": {\"scene\": {\"scene_str\": \""+sceneStr+"\"}}}";
            String result  = HttpClientUtil.doPostJson(getQrCodeUrl,json);
            JSONObject jsonObject = JSONObject.parseObject(result);
            jsonObject.put("sceneStr",sceneStr);
            return ResultJson.ok(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultJson.error(e.getMessage());
        }
    }
    /**
     *  获取accessToken
     * @return
     */
    public String getAccessToken(){
        String accessToken = null;
        log.info("getAccessToken 中的WxConfig: "+wxConfig.toString());
        String getTokenUrl = wxConfig.getTokenUrl().replace("APPID", wxConfig.getAppId()).replace("SECRET", wxConfig.getAppSecret());
        String result = HttpClientUtil.doGet(getTokenUrl);
        JSONObject jsonObject = JSONObject.parseObject(result);
        accessToken = jsonObject.getString("access_token");
        return accessToken ;
    }
    public WxConfig getWxConfig(){
        log.info(wxConfig.toString());
        return wxConfig;
    }
    /**
     *  验证签名
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping ("/checkSign")
    public String checkSign ( HttpServletRequest request) throws Exception {
        log.info("===========>checkSign");
        //获取微信请求参数
        //微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
        String signature = request.getParameter ("signature");
        //时间戳
        String timestamp = request.getParameter ("timestamp");
        //随机数
        String nonce = request.getParameter ("nonce");
        //随机字符串
        String echostr = request.getParameter ("echostr");
        //参数排序。 token 就要换成自己实际写的 token
        String [] params = new String [] {timestamp,nonce,"gzhmalldev"} ;
        Arrays.sort (params) ;
        //拼接
        String paramstr = params[0] + params[1] + params[2] ;
        //加密
        //获取 shal 算法封装类
        MessageDigest Sha1Dtgest = MessageDigest.getInstance("SHA-1") ;
        //进行加密
        byte [] digestResult = Sha1Dtgest.digest(paramstr.getBytes ("UTF-8"));
        //拿到加密结果
        String mysignature = CodeLoginUtil.bytes2HexString(digestResult);
        mysignature=mysignature.toLowerCase(Locale.ROOT);
        //是否正确
        boolean signsuccess = mysignature.equals(signature);
        //逻辑处理
        if (signsuccess && echostr!=null) {
            //peizhi  token
            log.info("checkSign 中的echostr 结果----"+echostr+" signsuccess的结果--- "+signsuccess);
            return echostr  ;//不正确就直接返回失败提示．
        }else{
            JSONObject jsonObject = callback(request);
            log.info("走了 callback ----");
            return jsonObject.toJSONString();
        }
    }


    /**
     *  回调方法
     * @param request
     * @return
     * @throws Exception
     */
    public JSONObject callback(HttpServletRequest request) throws Exception{
        log.info("===========>callback");
        //request中有相应的信息，进行解析
        WxMpXmlMessage message= WxMpXmlMessage.fromXml(request.getInputStream());//获取消息流,并解析xml
        String messageType=message.getMsgType();								//消息类型
        String messageEvent=message.getEvent();								    //消息事件
        // openid
        String fromUser=message.getFromUser();									//发送者帐号
        String touser=message.getToUser();										//开发者微信号
        String text=message.getContent();										//文本消息  文本内容
        // 生成二维码时穿过的特殊参数
        String eventKey=message.getEventKey();									//二维码参数

        String uuid="";															//从二维码参数中获取uuid通过该uuid可通过websocket前端传数据
        String userid="";

        //if判断，判断查询
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code","200");
        if(messageType.equals("event")){
            jsonObject = null;
            //先根据openid从数据库查询  => 从自己数据库中查取用户信息 => jsonObject
            if(messageEvent.equals("SCAN")){
                //扫描二维码
                //return "欢迎回来";
            }
            if(messageEvent.equals("subscribe")){
                //关注
//                return "谢谢您的关注";
            }
            //没有该用户
            if(jsonObject==null){
                //从微信上中拉取用户信息
                String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" +getAccessToken() +
                        "&openid=" + fromUser +
                        "&lang=zh_CN";
                String result = HttpClientUtil.doGet(url);
                jsonObject = JSONObject.parseObject(result);
                /**
                 * 用户信息处理....
                 */
            }
            // 扫码成功，存入缓存
            loginMap.put(eventKey,new CodeLoginKey(eventKey,fromUser));
            return jsonObject;
        }
        log.info("消息类型:{},消息事件:{},发送者账号:{},接收者微信:{},文本消息:{},二维码参数：{}",messageType,messageEvent,fromUser,touser,text,eventKey);
        return jsonObject;

    }

    /**
     *  根据二维码标识获取用户openId=>获取用户信息
     * @param eventKey
     * @return
     */
    @RequestMapping("/getOpenId")
    @CrudLog(title = "登录系统", businessType = BusinessType.INSERT)
    public R getOpenId(String eventKey) throws UnsupportedEncodingException {
        log.info(" 开始 getOpenId ----");
        log.info("Received eventKey: {}", eventKey);  // 添加日志打印 eventKey
        log.info("loginMap content: {}", loginMap);  // 打印 loginMap 内容
        if(loginMap.get(eventKey) == null){
            log.info("说明 eventKey为空  -----");
            return R.error("未扫码成功！") ;
        }
        CodeLoginKey codeLoginKey = loginMap.get(eventKey);
        loginMap.remove(eventKey);
        String openId = codeLoginKey.getOpenId();
        // 根据openId查询用户是否存在
        User user = userService.getUserByOpenId(openId);
        if (user == null) {
            // 如果用户不存在，则进行注册
            user = new User();
            user.setOpenId(openId);
            user.setUsername("wx_" + openId); // 设置默认用户名，可根据需求修改
            userService.save(user);
            //设置默认角色
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId().toString());
            userRole.setRoleId("3");
            userRoleService.save(userRole);
        }
        // 创建JWT token
        Subject subject = SecurityUtils.getSubject();
        String jwtToken = JWTUtil.createToken(user);
        JWTToken token = new JWTToken(jwtToken);
        subject.login(token); // Shiro登录验证

        List<Menu> menus = menuService.getUserMenus(user.getId());
        HashMap<String, Object> map = new HashMap<>();
        map.put("token",jwtToken );
        map.put("user",user);
        map.put("menus",menus);

        // 返回用户信息和token
        JSONObject result = new JSONObject();
        result.put("user", user);
        result.put("token", token);
        return R.ok().setData(map);
    }
    @RequestMapping("getBindOpenId")
    public R getBindOpenId(String eventKey){
        log.info(" 开始 getBindOpenId ----");
        log.info("Received eventKey: {}", eventKey);  // 添加日志打印 eventKey
        log.info("loginMap content: {}", loginMap);  // 打印 loginMap 内容
        if(loginMap.get(eventKey) == null){
            return R.error("未扫码成功！") ;
        }
        CodeLoginKey codeLoginKey = loginMap.get(eventKey);
        loginMap.remove(eventKey);
        JSONObject result = new JSONObject();
        result.put("codeLoginKey", codeLoginKey);

        return R.ok().setData(result);
    }
    @RequestMapping("/updateOpenId")
    public R getUpdateOpenId(@RequestParam(value = "userId") Integer Id,@RequestParam("openId") String openId){
        log.info("getUpdateOpenId中的id以及openId：Id={}, openId={}", Id, openId);
        // 检查是否有其他用户已经绑定了这个 openId
        User existingUser = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getOpenId, openId));
        if (existingUser != null) {
            // 如果 openId 已经被绑定到其他用户，则返回错误信息
            return R.error("该微信账号已绑定其他账号！");
        }

        // 如果没有其他用户绑定这个 openId，则更新当前用户的 openId
        User userToUpdate = userService.getById(Id);
        if (userToUpdate == null) {
            return R.error("用户不存在！");
        }

        userToUpdate.setOpenId(openId);
        userService.updateById(userToUpdate);
        User user2 = userService.getById(Id);
        JSONObject result = new JSONObject();
        result.put("user", user2);
        return R.ok("绑定成功！").setData(result);
    }
    @RequestMapping("unbindOpenId")
    public R unbindOpenId(@RequestParam(value = "userId") Integer userId){
        log.info("在走unbindOpenid");
        // 查找用户
        User user = userService.getById(userId);
        if (user == null) {
            return R.error("用户不存在！");
        }

        // 将openid置空

        userService.unbindOpenId(userId);
        User user2 = userService.getById(userId);
        // 返回用户信息和token
        JSONObject result = new JSONObject();
        result.put("user", user2);
        return R.ok("解除绑定成功！").setData(result);
    }

}

